#include "cc_mqtt.h"
#include "cc_wifi.h"
#include "cc_shell.h"
#include <WiFiClientSecure.h>

#if (CC_CONFIG_USE_MQTT && CC_CONFIG_USE_WIFI)

mqtt_topic_handle topic_sub_arr[CC_CONFIG_MAX_TOPIC_SUBSRIBE + 2];
mqtt_topic_handle* topic_sub_arr_start = topic_sub_arr;
mqtt_topic_handle* topic_sub_arr_end = topic_sub_arr;
#define foreach_subsricbe_topic(pos) \
  for (pos = topic_sub_arr_start; pos < topic_sub_arr_end; pos++)

uint8_t cc_mqtt_debug = 0;

const char* ip_addr = "broker.emqx.io";
const char* MQTT_USER_NAME = "emqx";
const char* MQTT_USE_PWD = "public";
const int MQTT_PORT = 8883;
const char* ca_cert = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----
)EOF";

WiFiClientSecure espClient;
PubSubClient mqtt_client = PubSubClient(espClient);

static uint8_t mqtt_topic_subsribe_cnt = 0;
void cc_topic_subsribe(mqtt_topic_handle_cb cb, char* topic)
{
  if (++mqtt_topic_subsribe_cnt > CC_CONFIG_MAX_TOPIC_SUBSRIBE + 2)
  {
    cc_log_e("topic:%s subsribe failed the sub arr is full\r\n", topic);
    cc_log_e("please inc the CC_CONFIG_MAX_TOPIC_SUBSRIBE in config.h\r\n");
    return;
  }
  mqtt_topic_handle* entry = topic_sub_arr_end;
  memcpy(entry->topic, topic, CC_CONFIG_COMPONENT_NAME_MAX);
  entry->cb = cb;
  topic_sub_arr_end += 1;
}

static void cc_topic_subsribe_all()
{
  mqtt_topic_handle* fn_ptr = topic_sub_arr_start;
  foreach_subsricbe_topic(fn_ptr)
  {
    if (strcmp(fn_ptr->topic, "") != 0)
    {
      cc_msg_mqtt_subsribe(fn_ptr->topic);
      cc_log("topic:%s subsribe success\r\n", fn_ptr->topic);
    }
  }
}

void mqtt_cc_shell(char* topic, char* msg, int length, int topic_len)
{
  if (cc_msg_send(CC_MSG_MQTT_NODE, msg, length, topic, topic_len))
  {
    cc_free(msg);
    msg = CC_NULL;
  }
}
CC_TOPIC_SUBSRIBE_ALIAS(mqtt_cc_shell, "cc_shell");

void mqtt_device_distr(char* topic, char* msg, int length, int topic_len)
{
  if (cc_msg_send(CC_MSG_MQTT_NODE, msg, length, topic, topic_len))
  {
    cc_free(msg);
    msg = CC_NULL;
  }
}
CC_TOPIC_SUBSRIBE_ALIAS(mqtt_device_distr, "device_distr");

void mqtt_sub_topics(char* param, int node)
{

  char result[800] = "";    // 初始化结果数组
  char temp[CC_CONFIG_MSG_TOPIC_MAX_LEN + 20];
  strcat(result, "------------subcribe topics-----------\r\n");
  mqtt_topic_handle* fn_ptr = topic_sub_arr_start;
  foreach_subsricbe_topic(fn_ptr)
  {
    if (strcmp(fn_ptr->topic, "") != 0)
    {
      sprintf(temp, "%s\r\n", fn_ptr->topic);
      strcat(result, temp);
    }
  }
  strcat(result, "------------------------------------\r\n");
  cc_msg_resp(node, result, 0, 0);
}
CC_COMMAND_SHELL(mqtt_sub_topics, "show all subsribes topic");

static int cc_can_data_trans()
{
  return cc_get_wifi_state() == CC_WIFI_CONNECTED;
}
int cc_msg_mqtt_publish(const char* topic, const char* data)
{
  if (strcmp(topic, "") == 0)
  {
    cc_log_e("topic is null\r\n");
    return CC_EINVAL;
  }
  if (cc_can_data_trans())
  {
    if (mqtt_client.publish(topic, data))
      return CC_EOK;
    else
      return CC_EINVAL;
  }
  else
  {
    cc_log_e("mqtt no connect:%d", mqtt_client.state());
    return CC_ENOTCONN;
  }
}
void cc_msg_mqtt_subsribe(const char* topic)
{
  if (cc_can_data_trans())
    mqtt_client.subscribe(topic);
  else
    cc_log_e("mqtt no connect:%d", mqtt_client.state());
}
static void cc_mqtt_callback(char* topic, byte* payload, unsigned int length);

int cc_msg_mqtt_init()
{
  static int cnt;
  int try_again_time = 1;
  espClient.setCACert(ca_cert);
  mqtt_client.setServer(ip_addr, MQTT_PORT);
  mqtt_client.setKeepAlive(60);
  mqtt_client.setCallback(cc_mqtt_callback);
  mqtt_client.setBufferSize(CC_CONFIG_MSG_MQTT_BUFFSIZE_MAX);
  if (cc_get_wifi_state() != CC_WIFI_CONNECTED)
  {
    cc_log_e("do not have network now,please check wifi\r\n");
    return -1;
  }

  while (!mqtt_client.connected())
  {
    cc_log("try mqtt connection...\r\n");
    // Attempt to connect
    if (mqtt_client.connect("cc_device_mqtt", MQTT_USER_NAME, MQTT_USE_PWD))
    {
      cc_log("connected success\r\n");
    }
    else
    {
      if (cnt++ >= 5)
      {
        cc_log_e("mqtt init failed:%d\r\n", mqtt_client.state());
        return -1;
      }
      cc_log_e("failed:%d\r\n", mqtt_client.state());
      cc_log_e("try again in %d seconds\r\n", try_again_time);
      // Wait 5 seconds before retrying
      cc_sleep(try_again_time * 1000);
    }
  }
  if (!cc_can_data_trans())
  {
    cc_log_e("mqtt not connect\r\n");
    return -1;
  }
  cc_msg_mqtt_publish("Device", "Init Successs\n");

  cc_topic_subsribe_all();
  return 1;
}
CC_INIT_COMPONENT_REGISTER(cc_msg_mqtt_init);

void cc_mqtt_loop_entry(void* data)
{
  if (cc_mqtt_debug)
    cc_log("into\r\n");
  int try_time;
  while (1)
  {
    // 如果wifi未连接 直接走就行
    if (!cc_can_data_trans())
    {
      goto failed;
    }
    if (!mqtt_client.connected())
    {
      cc_msg_mqtt_init();
    }
    mqtt_client.loop();
  failed:
    cc_delay(500);
  }
}
CC_THREAD_REGISTER_ALIAS(cc_mqtt_loop_entry, 20, 4096,"mqtt_entry");

void cc_mqtt_callback(char* topic, byte* payload, unsigned int length)
{
  if (!cc_can_data_trans())
  {
    cc_log_e("wifi not connect\r\n");
    return;
  }
  char* src_msg = (char*)cc_malloc(length + 1);
  char temp[100];
  memset(src_msg, 0, length + 1);
  int topic_len;
  while (topic[topic_len++] != '\0')
    ;
  topic_len--;
  for (int i = 0; i < length; i++)
  {
    src_msg[i] = (char)payload[i];
  }
  sprintf(temp, "topic:%s | len:%d | data:%s | len:%d\r\n", topic, topic_len,
          src_msg, length);
  if (cc_mqtt_debug)
  {
    cc_log("%s\r\n", temp);
  }

  mqtt_topic_handle* fn_ptr = topic_sub_arr_start;
  foreach_subsricbe_topic(fn_ptr)
  {
    if (strcmp(fn_ptr->topic, topic) == 0)
    {
      fn_ptr->cb(topic, src_msg, length, topic_len);
      break;
    }
  }
}

#if (LOG_D == 1)
void mqtt_debug(char* param, int node)
{
  cc_log_d("recv from node(%d):%s\r\n", node, param);
  if (cc_is_all_digits(param))
  {
    cc_mqtt_debug = atoi(param);
    if (cc_mqtt_debug < 0 || cc_mqtt_debug > 1)
    {
      cc_log_e("need 1 or 0\r\n");
      return;
    }
  }
  else
  {
    cc_log_e("need all digit param\r\n");
    return;
  }
  if (cc_mqtt_debug)
  {
    cc_msg_resp(node, "mqtt debug open\r\n", 0, 0);
  }
  else
  {
    cc_msg_resp(node, "mqtt debug clsoe\r\n", 0, 0);
  }
}
CC_COMMAND_SHELL(mqtt_debug, "enable(1) disable(0) mqtt debug printf");

int cc_get_mqtt_state()
{
  return mqtt_client.state();
}

void mqtt_publish(char* param, int node)
{
  char topic[CC_CONFIG_MSG_TOPIC_MAX_LEN];
  char msg[CC_CONFIG_MSG_DATA_MAX_LEN];
  memset(topic, 0, sizeof(topic));
  memset(msg, 0, sizeof(msg));
  int arg_cnt = cc_shell_parse_args(param, "%s %s", topic, msg);
  if (arg_cnt != 2)
  {
    cc_log_e("error param format please input format like (test hello)\r\n");
    return;
  }
  cc_log("publish to topic(%s) data(%s)\r\n", topic, msg);
  if (cc_msg_mqtt_publish(topic, msg) == CC_EOK)
  {
    // TODO 回复发送成功
  }
  else
  {
    // TODO 回复发送失败
  }
  return;
}
CC_COMMAND_SHELL(mqtt_publish, "mqtt publish(topic data)")
#endif

void mqtt_subsribe(char* param, int node)
{
  char topic[CC_CONFIG_MSG_TOPIC_MAX_LEN];
  int arg_cnt = cc_shell_parse_args(param, "%s %s", topic);
  if (arg_cnt != 1)
  {
    cc_log_e("error param format please input format like (test hello)\r\n");
    return;
  }
  cc_log("subsribe topic(%s)\r\n", topic);
  cc_msg_mqtt_subsribe(topic);
  return;
}
CC_COMMAND_SHELL(mqtt_subsribe, "mqtt subsribe(topic)")

#endif